/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using System.Xml;
using System.Collections.Generic;
using System.Qizx.Api;
using System.Qizx.Xml;
//using SequenceType = System.Qizx.Api.SequenceType;
using WordSieve = System.Qizx.Api.Indexing.WordSieve;
using FullTextFactory = System.Qizx.Api.FullText.FullTextFactory;
using DefaultFullTextFactory = System.Qizx.Api.Util.FullText.DefaultFullTextFactory;
using DefaultWordSieve = System.Qizx.Api.Util.DefaultWordSieve;
using BasicNode = System.Qizx.Xdm.BasicNode;
using FONIDataModel = System.Qizx.Xdm.FONIDataModel;
using ExtensionFunction = System.Qizx.XQuery.Ext.ExtensionFunction;
using System.Qizx.XQuery.Impl;

namespace System.Qizx.XQuery {


    public class XQuerySessionImpl : XQuerySession, MessageReceiver {
        virtual public XQueryContext Context {
            get {
                return xqContext;
            }

        }
        virtual public BasicStaticContext BasicContext {
            get {
                return xqContext;
            }

        }
        virtual public ModuleManager ModuleManager {
            get {
                return manager.ModuleManager;
            }

        }
        virtual public ModuleResolver ModuleResolver {
            get {
                return moduleResolver;
            }

            set {
                moduleResolver = value;
            }

        }
        virtual public Indexing.WordSieve WordSieve {
            get {
                return null;
            }

            set {
            }

        }
        virtual public FullTextFactory FullTextFactory {
            get {
                return fulltextProvider;
            }

            set {
                this.fulltextProvider = value;
            }

        }
        private XQuerySessionManager manager;
        private BasicStaticContext xqContext;
        private ItemFactory itemMaker;
        private int errorCount;
        private System.Collections.Generic.List<Message> messages = new List<Message>();
        private QName firstErrorCode;
        private QName latestErrorCode;
        private ModuleResolver moduleResolver; // optional

        protected internal FullTextFactory fulltextProvider;

        public XQuerySessionImpl(XQuerySessionManager manager) {
            this.manager = manager;
            xqContext = new BasicStaticContext();
            itemMaker = new ItemFactoryImpl();
            // plug extension functions:
            PredefinedModule predef = xqContext.PredefinedModule;
            string xuri = ExtensionFunction.EXTENSIONS_NS;
            predef.registerFunctionPlugger(new PredefinedModule.BasicFunctionPlugger(xuri, "System.Qizx.XQuery.Ext.Xfn%C"));
            xqContext.DeclarePrefix(ExtensionFunction.EXTENSIONS_PREFIX, xuri);
            xqContext.DeclarePrefix(ExtensionFunction.EXTENSIONS_PREFIX_QIZX, xuri);
            // full-text namespace ft: is a mere alias of x:
            xqContext.DeclarePrefix("ft", xuri);
            fulltextProvider = new DefaultFullTextFactory();
        }


        public virtual Expression CompileExpression(string xquerySource) {
            return Compile(xquerySource, xqContext, null);
        }

        public virtual Expression CompileExpression(string xquerySource, IXmlNamespaceResolver resolver) {
            return Compile(xquerySource, xqContext, resolver);
        }

        internal virtual ExpressionImpl Compile(string xquerySource, BasicStaticContext context, IXmlNamespaceResolver resolver) {
            // create a context:
            MainQuery query = new MainQuery(context, resolver);
            query.MessageTarget = this;
            firstErrorCode = latestErrorCode = null;
            errorCount = 0;
            messages.Clear();

            ModuleManager modMan = manager.ModuleManager;
            // parse the source code:
            NewParser parser = new NewParser(modMan);
            if (moduleResolver != null)
                parser.setModuleResolver(moduleResolver);
            query.FulltextProvider = fulltextProvider;

            try {
                parser.parseQuery(query, xquerySource, null);
            } catch (CompilationException err) {
                err.Messages = messages.ToArray();
                throw err;
            }

            //        // Static checking:
            //        XQItem currentItem = null; // todo ?
            //
            //        if (currentItem != null)
            //            query.pushDotType(currentItem.getItemType());

            if (errorCount == 0)
                query.StaticCheck(modMan);

            //        if (currentItem != null)
            //            query.popDotType();

            if (errorCount > 0) {
                CompilationException err = new CompilationException(errorCount + " error(s) in static analysis");
                //            if (latestErrorCode != null)
                //                err.setErrorCode(latestErrorCode);
                if (firstErrorCode != null)
                    err.setErrorCode(firstErrorCode);
                err.Messages = (Message[])messages.ToArray();
                throw err;
            }

            ExpressionImpl expr = new ExpressionImpl(new DynamicContext(query, this), query);
            return expr;
        }

        public virtual void Receive(Message message) {
            messages.Add(message);
            if (message.Type == Message.ERROR) {
                ++errorCount;
                if (message.ErrorCode != null) {
                    if (firstErrorCode == null)
                        firstErrorCode = message.ErrorCode;
                    latestErrorCode = message.ErrorCode;
                }
            }
        }

        public virtual ItemSequence CopySequence(ItemSequence sequence) {
            return itemMaker.CopySequence(sequence);
        }

        public virtual Item CreateItem(bool value) {
            return itemMaker.CreateItem(value);
        }

        public virtual Item CreateItem(double value) {
            return itemMaker.CreateItem(value);
        }

        public virtual Item CreateItem(float value) {
            return itemMaker.CreateItem(value);
        }

        public virtual Item CreateItem(XmlSource source) {
            return itemMaker.CreateItem(source);
        }

        public virtual Item CreateItem(long value, ItemType type) {
            return itemMaker.CreateItem(value, type);
        }

        public virtual Item CreateItem(System.Object value, ItemType type) {
            return itemMaker.CreateItem(value, type);
        }

        public virtual Item CreateItem(XMLPullStream source) {
            return itemMaker.CreateItem(source);
        }

        public virtual ItemSequence CreateSequence(System.Object obj, ISequenceType type) {
            return itemMaker.CreateSequence(obj, type);
        }

        public virtual QName GetQName(string localName, string namespaceURI, string prefix) {
            return itemMaker.GetQName(localName, namespaceURI, prefix);
        }

        public virtual QName GetQName(string localName, string namespaceURI) {
            return itemMaker.GetQName(localName, namespaceURI);
        }

        public virtual QName GetQName(string localName) {
            return itemMaker.GetQName(localName);
        }

        public virtual ItemType GetType(string name) {
            return itemMaker.GetType(name);
        }

        public virtual BasicNode GetDocument(string uri) {
            FONIDataModel doc = manager.DocumentCache.findDocument(uri);
            return doc == null ? null : doc.DocumentNode;
        }

        public virtual void EnableJavaBinding(string className) {
            xqContext.PredefinedModule.authorizeJavaClass(className);
        }
    }
}